﻿using System;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using CrateMayhem.Common.Controls;
using CrateMayhem.Common.Data;
using CrateMayhem.Common.Services;

namespace CrateMayhem.Desktop.Controls
{
    public class GameGrid : Grid, IGridContainer
    {
        private readonly GameGridManager manager;

        public static readonly DependencyProperty LevelProperty =
            DependencyProperty.Register(
                "Level", typeof(int), typeof(GameGrid), new PropertyMetadata(0, OnLevelPropertyChanged));

        public GameGrid()
        {
            try
            {
                var serviceFactory = Global.Container.Resolve<IServiceFactory>();
                var worldRepository = Global.Container.Resolve<IWorldRepository>();
                manager = new GameGridManager(this, serviceFactory, worldRepository) { Children = Children };
            }
            catch (Exception)
            {
            }
        }

        public int Level
        {
            get { return (int)GetValue(LevelProperty); }
            set { SetValue(LevelProperty, value); }
        }

        public int GetRow(IMapControl control)
        {
            return GetRow((FrameworkElement)control);
        }

        public int GetColumn(IMapControl control)
        {
            return GetColumn((FrameworkElement)control);
        }

        public void SetRow(IMapControl control, int row)
        {
            SetRow((FrameworkElement)control, row);
        }

        public void SetColumn(IMapControl control, int column)
        {
            SetColumn((FrameworkElement)control, column);
        }

        public void InitGrid()
        {
            if (!RowDefinitions.Any())
            {
                for (var i = 0; i < GameGridManager.OverallMaxRows; i++)
                {
                    RowDefinitions.Add(new RowDefinition());
                }

                for (var i = 0; i < GameGridManager.OverallMaxCols; i++)
                {
                    ColumnDefinitions.Add(new ColumnDefinition());
                }
            }
        }

        private static void OnLevelPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var grid = (GameGrid)d;
            grid.InitGrid();
            BuildGameLevel(grid, (int)e.NewValue);
            grid.manager.HighlightCratesOnTarget();
        }

        private static void AddGridItem<T>(Grid grid, int row, int col) where T : FrameworkElement, new()
        {
            var item = new T();
            grid.Children.Add(item);
            SetRow(item, row);
            SetColumn(item, col);
        }

        private static void BuildGameLevel(GameGrid grid, int level)
        {
            grid.Children.Clear();
            grid.manager.ClearMoves();

            var world = grid.manager.Worlds.FirstOrDefault(w => w.Level == level);

            if (world == null) return;

            var rowOffset = (GameGridManager.OverallMaxRows - world.Layout.Count()) / 2;
            var colOffset = (GameGridManager.OverallMaxCols - world.Layout.Max(l => l.Length)) / 2;

            grid.Width = GameGridManager.OverallMaxCols * GameGridManager.CrateSize;
            grid.Height = GameGridManager.OverallMaxRows * GameGridManager.CrateSize;

            world.AddMatchingParts(grid, rowOffset, colOffset, '#', AddGridItem<Brick>);
            world.AddMatchingParts(grid, rowOffset, colOffset, '.', AddGridItem<CrateTarget>);
            world.AddMatchingParts(grid, rowOffset, colOffset, '*', AddGridItem<CrateTarget>);
            world.AddMatchingParts(grid, rowOffset, colOffset, '$', AddGridItem<Crate>);
            world.AddMatchingParts(grid, rowOffset, colOffset, '*', AddGridItem<Crate>);
            world.AddMatchingParts(grid, rowOffset, colOffset, '@', AddGridItem<Worker>);
        }
    }
}